package com.peiwangroup.gateway.filter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;

@Component
public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAuthenticationFilter.Config> {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    @Value("${jwt.secret}")
    private String jwtSecret;

    public JwtAuthenticationFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            
            logger.info("Processing request for path: {}", path);
            logger.info("Request headers: {}", request.getHeaders());
            
            // 检查是否是公开路径
            if (isSecured.test(request)) {
                if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                    logger.warn("No Authorization header found for secured path: {}", path);
                    return unauthorized(exchange);
                }

                String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
                if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                    logger.warn("Invalid Authorization header format for path: {}", path);
                    return unauthorized(exchange);
                }

                String token = authHeader.substring(7);
                try {
                    logger.info("Validating JWT token: {}", token);
                    logger.info("Using JWT secret: {}", jwtSecret);
                    
                    SecretKey key = Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8));
                    Claims claims = Jwts.parserBuilder()
                            .setSigningKey(key)
                            .build()
                            .parseClaimsJws(token)
                            .getBody();

                    String username = claims.getSubject();
                    String permission = claims.get("permission", String.class);

                    logger.info("Successfully authenticated user: {} with permission: {}", username, permission);
                    logger.info("JWT claims: {}", claims);

                    // 检查权限
                    if (path.startsWith("/api/users/") && !"admin".equals(permission)) {
                        // 允许普通用户访问自己的密码修改接口
                        if (path.matches("/api/users/[^/]+/password") && path.contains(username)) {
                            logger.info("Allowing user {} to access their own password update endpoint", username);
                        } else {
                            logger.warn("User {} with permission {} attempted to access admin path: {}", username, permission, path);
                            return forbidden(exchange);
                        }
                    }

                    // 将用户信息和权限添加到请求头中
                    ServerHttpRequest modifiedRequest = request.mutate()
                            .header("X-User-Username", username)
                            .header("X-User-Permission", permission)
                            .header("X-User-Authorities", permission)
                            .build();

                    logger.info("Modified request headers: {}", modifiedRequest.getHeaders());
                    return chain.filter(exchange.mutate().request(modifiedRequest).build());
                } catch (Exception e) {
                    logger.error("JWT validation failed for path: {}", path, e);
                    logger.error("JWT token: {}", token);
                    logger.error("JWT secret: {}", jwtSecret);
                    return unauthorized(exchange);
                }
            }
            
            logger.info("Skipping JWT validation for public path: {}", path);
            return chain.filter(exchange);
        };
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange) {
        logger.warn("Returning 401 Unauthorized response");
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }

    private Mono<Void> forbidden(ServerWebExchange exchange) {
        logger.warn("Returning 403 Forbidden response");
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        return exchange.getResponse().setComplete();
    }

    public static class Config {
        // 可以添加配置属性
    }

    private final Predicate<ServerHttpRequest> isSecured = request -> {
        String path = request.getURI().getPath();
        return !path.startsWith("/api/auth/") && 
               !path.equals("/api/users/register") &&
               !path.startsWith("/api/wechat/") &&
               !path.equals("/actuator/health");
    };
} 